/**
 * Copyright (c) 2008, Mu Dynamics.
 *  All rights reserved.
 *  
 *   Redistribution and use in source and binary forms, with or without modification, 
 *   are permitted provided that the following conditions are met:
 *   
 *  - Redistributions of source code must retain the above copyright notice, 
 *     this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice, 
 *     this list of conditions and the following disclaimer in the documentation and/or 
 *     other materials provided with the distribution.
 *  - Neither the name of the "Mu Dynamics" nor the names of its contributors may be used 
 *     to endorse  or promote products derived from this software without specific prior 
 *     written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.mu.jacob.core.model.decorator;

import java.util.ArrayList;
import java.util.List;

import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.NoType;
import javax.lang.model.type.NullType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.Types;

import com.mu.jacob.core.generator.Decorate;

/**
 * Types decorator
 * @author Adam Smyczek
 *
 */
public class DefaultTypes extends DefaultDecorator<Types> implements Types {

	/** decorated types */
	private Types types;
	
	/**
	 * @see com.mu.jacob.core.model.decorator.DefaultDecorator#getDecorated()
	 */
	public Types getDecorated() {
		return types;
	}

	/**
	 * @see com.mu.jacob.core.model.decorator.DefaultDecorator#getApiClass()
	 */
	public final Class<Types> getApiClass() {
		return Types.class;
	}

	/**
	 * @see com.mu.jacob.core.model.decorator.DefaultDecorator#initialize(java.lang.Object)
	 */
	public void initialize(Types model) {
		this.types = model;
	}

	/**
	 * @see javax.lang.model.util.Types#asElement(javax.lang.model.type.TypeMirror)
	 */
	@Decorate
	public Element asElement(TypeMirror t) {
		return types.asElement(undeco(t));
	}

	/**
	 * @see javax.lang.model.util.Types#getNoType(javax.lang.model.type.TypeKind)
	 */
	@Decorate
	public NoType getNoType(TypeKind kind) {
		return types.getNoType(kind);
	}

	/**
	 * @see javax.lang.model.util.Types#asMemberOf(javax.lang.model.type.DeclaredType, javax.lang.model.element.Element)
	 */
	@Decorate
	public TypeMirror asMemberOf(DeclaredType containing, Element element) {
		return types.asMemberOf(undeco(containing), undeco(element));
	}

	/**
	 * @see javax.lang.model.util.Types#boxedClass(javax.lang.model.type.PrimitiveType)
	 */
	@Decorate
	public TypeElement boxedClass(PrimitiveType p) {
		return types.boxedClass(undeco(p));
	}

	/**
	 * @see javax.lang.model.util.Types#capture(javax.lang.model.type.TypeMirror)
	 */
	@Decorate
	public TypeMirror capture(TypeMirror t) {
		return types.capture(undeco(t));
	}

	/**
	 * @see javax.lang.model.util.Types#contains(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror)
	 */
	public boolean contains(TypeMirror t1, TypeMirror t2) {
		return types.contains(undeco(t1), undeco(t2));
	}

	/**
	 * @see javax.lang.model.util.Types#directSupertypes(javax.lang.model.type.TypeMirror)
	 */
	@Decorate
	public List<? extends TypeMirror> directSupertypes(TypeMirror t) {
		return types.directSupertypes(undeco(t));
	}

	/**
	 * @see javax.lang.model.util.Types#erasure(javax.lang.model.type.TypeMirror)
	 */
	@Decorate
	public TypeMirror erasure(TypeMirror t) {
		return types.erasure(undeco(t));
	}

	/**
	 * @see javax.lang.model.util.Types#getArrayType(javax.lang.model.type.TypeMirror)
	 */
	@Decorate
	public ArrayType getArrayType(TypeMirror componentType) {
		return types.getArrayType(undeco(componentType));
	}

	/**
	 * @see javax.lang.model.util.Types#getDeclaredType(javax.lang.model.type.DeclaredType, javax.lang.model.element.TypeElement, javax.lang.model.type.TypeMirror[])
	 */
	@Decorate
	public DeclaredType getDeclaredType(DeclaredType containing, TypeElement typeElem, TypeMirror... typeArgs) {
		List<TypeMirror> tas = new ArrayList<TypeMirror>();
		for (TypeMirror tm : typeArgs) tas.add(undeco(tm));
		return types.getDeclaredType(undeco(containing), undeco(typeElem), tas.toArray(new TypeMirror[0]));
	}

	/**
	 * @see javax.lang.model.util.Types#getDeclaredType(javax.lang.model.element.TypeElement, javax.lang.model.type.TypeMirror[])
	 */
	@Decorate
	public DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) {
		List<TypeMirror> tas = new ArrayList<TypeMirror>();
		for (TypeMirror tm : typeArgs) tas.add(undeco(tm));
		return types.getDeclaredType(undeco(typeElem), tas.toArray(new TypeMirror[0]));
	}

	/**
	 * @see javax.lang.model.util.Types#getNullType()
	 */
	@Decorate
	public NullType getNullType() {
		return types.getNullType();
	}

	/**
	 * @see javax.lang.model.util.Types#getPrimitiveType(javax.lang.model.type.TypeKind)
	 */
	@Decorate
	public PrimitiveType getPrimitiveType(TypeKind kind) {
		return types.getPrimitiveType(kind);
	}

	/**
	 * @see javax.lang.model.util.Types#getWildcardType(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror)
	 */
	@Decorate
	public WildcardType getWildcardType(TypeMirror extendsBound, TypeMirror superBound) {
		return types.getWildcardType(undeco(extendsBound), undeco(superBound));
	}

	/**
	 * @see javax.lang.model.util.Types#isAssignable(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror)
	 */
	public boolean isAssignable(TypeMirror t1, TypeMirror t2) {
		return types.isAssignable(undeco(t1), undeco(t2));
	}

	/**
	 * @see javax.lang.model.util.Types#isSameType(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror)
	 */
	public boolean isSameType(TypeMirror t1, TypeMirror t2) {
		return types.isSameType(undeco(t1), undeco(t2));
	}

	/**
	 * @see javax.lang.model.util.Types#isSubsignature(javax.lang.model.type.ExecutableType, javax.lang.model.type.ExecutableType)
	 */
	public boolean isSubsignature(ExecutableType m1, ExecutableType m2) {
		return types.isSubsignature(undeco(m1), undeco(m2));
	}

	/**
	 * @see javax.lang.model.util.Types#isSubtype(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror)
	 */
	public boolean isSubtype(TypeMirror t1, TypeMirror t2) {
		return types.isSubtype(undeco(t1), undeco(t2));
	}

	/**
	 * @see javax.lang.model.util.Types#unboxedType(javax.lang.model.type.TypeMirror)
	 */
	@Decorate
	public PrimitiveType unboxedType(TypeMirror t) {
		return types.unboxedType(undeco(t));
	}

}
